package com.jintian.smart.kernel.flowable.component;

import com.jintian.smart.kernel.common.util.StringUtil;
import com.jintian.smart.kernel.core.flow.*;
import org.apache.dubbo.config.annotation.DubboService;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.task.api.TaskInfo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@DubboService(timeout = 5000)
public class DefaultProcessOperation implements IProcessOperation<List<TaskInfo>>, BeanPostProcessor {
    @Autowired
    private ProcessEngine processEngine;
    private static final Map<FlowAction, IProcessAction<?>> actionMap = new HashMap<>();

    @Override
    public void registerProcessAction(FlowAction action, IProcessAction<?> taskAction) {
        if (action.isActionType(ActionType.process)) {
            actionMap.put(action, taskAction);
        }
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof IProcessAction) {
            @SuppressWarnings("rawtypes")
            IProcessAction ta = (IProcessAction) bean;
            this.registerProcessAction(ta.getAction(), ta);
        }
        return bean;
    }

    @Override
    public IProcessAction<?> getAction(FlowAction flowAction) {
        return actionMap.get(flowAction);
    }

    @Override
    public void suspend(String processInstanceId, ProcessControl ProcessControl) throws Exception {
        actionMap.get(FlowAction.suspend).execute(processInstanceId, ProcessControl);
    }

    @Override
    public void resume(String processInstanceId, ProcessControl ProcessControl) throws Exception {
        actionMap.get(FlowAction.resume).execute(processInstanceId, ProcessControl);
    }

    @Override
    public void abort(String processInstanceId, ProcessControl ProcessControl) throws Exception {
        actionMap.get(FlowAction.abort).execute(processInstanceId, ProcessControl);
    }

    @Override
    public void delete(String processInstanceId, ProcessControl ProcessControl) throws Exception {
        actionMap.get(FlowAction.delete).execute(processInstanceId, ProcessControl);
    }

    @Override
    public void delete(String bizId, String bizClass, String process) throws Exception {
        HistoricProcessInstanceQuery query = processEngine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceBusinessKey(bizId);
        if (StringUtil.isNoneBlank(process)) {
            query = query.processDefinitionKey(process);
        }
        if (StringUtil.isNoneBlank(bizClass)) {
            query = query.variableValueEquals(FlowAction.VARNAME_START_BIZCLASS, bizClass);
        }
        List<HistoricProcessInstance> list = query.orderByProcessInstanceStartTime().desc().list();
        if (list != null && list.size() > 1) {
            throw new FlowableException("当前业务存在多个流程实例，请指定流程id");
        }

        if (list != null && list.size() == 1) {
            HistoricProcessInstance pi = list.get(0);
            this.delete(pi.getId(), null);
        }
    }

    @Override
    public void empty() {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        HistoryService historyService = processEngine.getHistoryService();
        // 删除运行中的实例
        runtimeService.createProcessInstanceQuery().list()
                .forEach(instance -> {
                    runtimeService.deleteProcessInstance(instance.getId(), "系统级批量清理");
                    historyService.deleteHistoricProcessInstance(instance.getId());
                });

        // 清理残留的历史实例（可能存在的未关联运行实例）
        historyService.createHistoricProcessInstanceQuery().list()
                .forEach(instance -> {
                    historyService.deleteHistoricProcessInstance(instance.getId());
                });
    }

    public ProcessControl queryProcessControl(String taskId, String action, Map<String, Object> transientVariables) throws Exception {
        return actionMap.get(FlowAction.valueOf(action)).queryProcessControl(taskId, transientVariables);
    }
}
